package cn.edu.dlmu.cogo.framework.data;

import cn.edu.dlmu.cogo.framework.config.DataBaseConfig;
import cn.edu.dlmu.cogo.framework.config.JavaConfig;
import cn.edu.dlmu.cogo.framework.context.Environment;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;

import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author yixi
 */
public class DataBaseSession {

    private final boolean enableCache;

    public DataBaseSession() {
        DataBaseConfig config = JavaConfig.getConfig(DataBaseConfig.class);
        int cacheSize = config.getCacheSize();
        long cacheUnit = config.getCacheUnit();
        enableCache = cacheSize != -1 && cacheUnit != -1;
        if (enableCache) {
            SessionCache.initialize(cacheSize,cacheUnit);
        }
    }

    public boolean beginTransaction(Action... actions){
        try {
            Db.use(DataBaseSource.getDataSource()).tx(db -> {
                for (Action action : actions) {
                    modify(action);
                }
            });
            return true;
        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        }
    }

    public boolean modify(Action action){
        return modify(action.getSql(),action.getParams());
    }

    public boolean modify(String sql,Object... params){
        Console.log(sql,params);
        try {
            int execute = Db.use(DataBaseSource.getDataSource()).execute(sql, params);
            return execute != 0;
        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        }
    }

    public Number findCount(Action action){
        return findCount(action.getSql(),action.getParams());
    }

    public Number findCount(String sql,Object ... params){
        try {
            return Db.use(DataBaseSource.getDataSource()).queryNumber(sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }

    public String findString(Action action){
        return findString(action.getSql(), action.getParams());
    }

    public String findString(String sql,Object ... params){
        try {
            return Db.use(DataBaseSource.getDataSource()).queryString(sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }

    public <T> T findOne(Class<T> clazz,Action action){
        return findOne(clazz,action.getSql(),action.getParams());
    }

    public <T> T findOne(Class<T> clazz,String sql,Object ... params){
        return findList(clazz,sql,params).get(0);
    }

    public <T> List<T> findList(Class<T> clazz,Action action){
        return findList(clazz,action.getSql(),action.getParams());
    }

    public <T> List<T> findList(Class<T> clazz,String sql,Object ... params){
        Action action = new Action().setSql(sql).setParams(params);
        if (enableCache){
            List<T> cache = (List<T>) SessionCache.getCache(action);
            if (cache != null) {
                Console.log("{} [CogoData]本地缓存取值成功[{}][{}]", Environment.getSystemTime(), sql, params);
                return cache;
            }else {
                Console.error("{} [CogoData]本地缓存取值失败[{}][{}]",Environment.getSystemTime(), sql, params);
            }
        }
        Console.log(sql,params);
        //获取对象字段信息
        T t;
        List<Entity> query;
        List<T> tList = new ArrayList<>();
        BeanInfo beanInfo = new BeanInfo(clazz);
        List<Field> fields = beanInfo.getFieldNames();
        List<String> columnNames = beanInfo.getColumnNames();
        List<Class<?>> fieldTypes = beanInfo.getFieldTypes();
        //开始执行查询操作
        try {
            query = Db.use(DataBaseSource.getDataSource()).query(sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
        //进行实体类字段映射转换
        for (Entity entity : query) {
            t = ReflectUtil.newInstance(clazz);
            Object value = null;
            for (int i = 0; i < fieldTypes.size(); i++) {
                if (fieldTypes.get(i) == String.class) {
                    value = entity.getStr(columnNames.get(i));
                }else if (fieldTypes.get(i) == int.class || fieldTypes.get(i) == Integer.class) {
                    value = entity.getInt(columnNames.get(i));
                }else if (fieldTypes.get(i) == double.class || fieldTypes.get(i) == Double.class) {
                    value = entity.getDouble(columnNames.get(i));
                }else if (fieldTypes.get(i) == boolean.class || fieldTypes.get(i) == Boolean.class) {
                    value = entity.getBool(columnNames.get(i));
                }else if (fieldTypes.get(i) == float.class || fieldTypes.get(i) == Float.class) {
                    value = entity.getFloat(columnNames.get(i));
                }
                ReflectUtil.setFieldValue(t, fields.get(i), value);
            }
            tList.add(t);
        }
        if (enableCache){
            SessionCache.setCache(action,tList);
        }
        return tList;
    }
}
